''' <summary>
''' This is a game component that implements IUpdateable.
''' </summary>
''' 

Public NotInheritable Class JumpType
    Public Shared Normal1 As Color = New Color(255, 255, 255)
    Public Shared Normal2 As Color = New Color(166, 166, 166)
    Public Shared Hole As Color = New Color(0, 0, 0)
    Public Shared Slow As Color = New Color(255, 0, 0)
    Public Shared Fast As Color = New Color(255, 255, 0)
    Public Shared Jump As Color = New Color(0, 0, 255)
    Public Shared Stuck As Color = New Color(0, 255, 0)
    Public Shared Normal3 As Color = New Color(245, 207, 146)
    Public Shared Normal4 As Color = New Color(100, 80, 45)
    Public Shared Reverse As Color = New Color(246, 0, 246)
    Public Sub New()

    End Sub
End Class
Public Class GameLevel
    Inherits Microsoft.Xna.Framework.DrawableGameComponent
    Private mdatLevel() As Color = Nothing
    Private mVertex() As VertexPositionColor
    Private mVBuffer As DynamicVertexBuffer
    Private mUnitSize As Single
    Private mstrLevel As String
    Private mWidth As Integer
    Private mGameRun As IGameProto
    Private mblnLevelNotified As Boolean

    Public Event EndOfLevel()
    Public Property RowCount As Integer

    Public Sub New(ByVal game As Game, ByVal GameRun As IGameProto)
        MyBase.New(game)
        mGameRun = GameRun
        ' TODO: Construct any child components here
        Me.RowCount = 50
    End Sub
    ' ///////////////////////////////////////////////////////////////////////////////////
    ' Load the content
    Protected Overrides Sub LoadContent()
        MyBase.LoadContent()
    End Sub
    ' ///////////////////////////////////////////////////////////////////////////////////
    ' Draw the level.
    Public Overrides Sub Draw(gameTime As Microsoft.Xna.Framework.GameTime)
        If (Not mVBuffer Is Nothing) Then
            mGameRun.Effect.CurrentTechnique.Passes(0).Apply()
            GraphicsDevice.SetVertexBuffer(mVBuffer)
            GraphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, CInt(mVertex.Count / 3))
        End If
        MyBase.Draw(gameTime)
    End Sub
    ' ///////////////////////////////////////////////////////////////////////////////////
    Public Function CheckSquare(ByRef Location As Vector3) As Color
        Dim sngX As Single = Location.X
        Dim sngZ As Single = Location.Z
        Dim intCol As Integer = CInt((sngX - sngX Mod mUnitSize) / mUnitSize)
        Dim intRow As Integer = CInt((sngZ - sngZ Mod mUnitSize) / mUnitSize)
        Dim colReturn As Color

        intRow = intRow - Me.RowCount
        ' End of level?
        If (intRow <= 0 Or intRow * mWidth + intCol >= mdatLevel.Count) Then
            Return JumpType.Normal1
        End If
        ' Get Colour
        colReturn = mdatLevel(intRow * mWidth + intCol)
        If (colReturn = JumpType.Hole) Then
            sngX -= CSng(mUnitSize * 0.1)
            intCol = CInt((sngX - sngX Mod mUnitSize) / mUnitSize)
            colReturn = mdatLevel(intRow * mWidth + intCol)
            If (colReturn <> JumpType.Hole) Then
                Return colReturn
            End If
            sngX += CSng(mUnitSize * 0.1) * 2
            intCol = CInt((sngX - sngX Mod mUnitSize) / mUnitSize)
            colReturn = mdatLevel(intRow * mWidth + intCol)
            If (colReturn <> JumpType.Hole) Then
                Return colReturn
            End If
        End If
        Return colReturn
    End Function
    ' ///////////////////////////////////////////////////////////////////////////////////
    ' Load the level information specified
    Public Sub LoadLevel(ByVal strLevel As String)
        Dim intRow As Integer
        Dim intCol As Integer
        Dim blnFront As Boolean
        Dim blnLeft As Boolean
        Dim colColour As Color
        Dim blnRight As Boolean
        Dim tex As Texture2D = Game.Content.Load(Of Texture2D)(strLevel)

        ' Clear the existing buffer
        mdatLevel = Nothing
        mVertex = Nothing
        mVBuffer = Nothing
        ' Load that information in.
        mUnitSize = mGameRun.UnitSize
        mdatLevel = New Color(tex.Width * tex.Height - 1) {}
        tex.GetData(mdatLevel)
        ' We need to go through each of the pixels and transfer it into polygons
        For intRow = 0 To tex.Height - 1
            For intCol = 0 To tex.Width - 1
                colColour = mdatLevel(tex.Width * intRow + intCol)
                blnLeft = intCol = 0
                If (Not blnLeft And intCol > 0) Then
                    blnLeft = mdatLevel(tex.Width * intRow + intCol - 1) = JumpType.Hole
                End If
                blnRight = intCol = tex.Width - 1
                If (Not blnRight And intCol < tex.Width - 1) Then
                    blnRight = mdatLevel(tex.Width * intRow + intCol + 1) = JumpType.Hole
                End If
                blnFront = False
                If (intRow > 0) Then
                    blnFront = mdatLevel(tex.Width * (intRow - 1) + intCol) = JumpType.Hole
                End If
                CreateCell(intCol, intRow + Me.RowCount, colColour, blnLeft, blnRight, blnFront)
            Next
        Next
        '  The first two rows are copied across the number of rows there are in the distance
        For intRow = 0 To Me.RowCount - 1
            For intCol = 0 To tex.Width - 1
                CreateCell(intCol, intRow, mdatLevel(tex.Width * (intRow Mod 2) + intCol), intCol = 0, intCol = tex.Width - 1, False)
            Next
        Next
        ' Again copy the last two rows for the distance amount.
        For intRow = 0 To Me.RowCount - 1
            For intCol = 0 To tex.Width - 1
                CreateCell(intCol, intRow + Me.RowCount + tex.Height, mdatLevel(tex.Width * (intRow Mod 2) + intCol + ((tex.Height - 2) * tex.Width)), intCol = 0, intCol = tex.Width - 1, False)
            Next
        Next
        ' Reset the end of level notify flag
        mblnLevelNotified = False
        ' Create the vertex buffer
        mVBuffer = New DynamicVertexBuffer(GraphicsDevice, VertexPositionColor.VertexDeclaration, mVertex.Count, BufferUsage.None)
        mVBuffer.SetData(Of VertexPositionColor)(mVertex)
        ' Clean up
        mWidth = tex.Width
        tex = Nothing
    End Sub
    ' ///////////////////////////////////////////////////////////////////////////////////
    ' Creates a double polygon
    Public Sub CreateCell(ByVal intX As Integer, ByVal intZ As Integer, ByVal colColour As Color, ByVal blnLeft As Boolean, ByVal blnRight As Boolean, ByVal blnFront As Boolean)
        If (colColour = JumpType.Hole) Then
            Return
        End If
        Dim intY As Single = 0
        Dim intCounter As Integer
        Dim intStart As Integer = 0
        If (Not mVertex Is Nothing) Then
            intStart = mVertex.Count
        End If
        Dim colColour2 As Color = Color.Lerp(colColour, Color.Black, 0.6)
        Dim colColour3 As Color = Color.Lerp(colColour, Color.White, 0.4)
        Dim colColour4 As Color = Color.Lerp(colColour, Color.Black, 0.4)
        Dim sngYLower As Single = intY - CSng(mUnitSize / 4.0)
        ReDim Preserve mVertex(intStart + 6 * (1 + Math.Abs(CInt(blnFront) + CInt(blnRight) + CInt(blnLeft))) - 1)

        If (colColour <> Color.Black) Then
            mVertex(intStart).Color = colColour : mVertex(intStart).Position = New Vector3(intX * mUnitSize + mUnitSize, intY, intZ * mUnitSize)
            mVertex(intStart + 1).Color = colColour : mVertex(intStart + 1).Position = New Vector3(intX * mUnitSize, intY, intZ * mUnitSize + mUnitSize)
            mVertex(intStart + 2).Color = colColour : mVertex(intStart + 2).Position = New Vector3(intX * mUnitSize, intY, intZ * mUnitSize)
            mVertex(intStart + 3).Color = colColour : mVertex(intStart + 3).Position = New Vector3(intX * mUnitSize + mUnitSize, intY, intZ * mUnitSize)
            mVertex(intStart + 4).Color = colColour : mVertex(intStart + 4).Position = New Vector3(intX * mUnitSize + mUnitSize, intY, intZ * mUnitSize + mUnitSize)
            mVertex(intStart + 5).Color = colColour : mVertex(intStart + 5).Position = New Vector3(intX * mUnitSize, intY, intZ * mUnitSize + mUnitSize)
            intCounter = 6
            ' Front Side
            If (blnFront) Then
                mVertex(intStart + intCounter).Color = colColour2 : mVertex(intStart + intCounter).Position = New Vector3(intX * mUnitSize + mUnitSize, sngYLower, intZ * mUnitSize)
                mVertex(intStart + intCounter + 1).Color = colColour2 : mVertex(intStart + intCounter + 1).Position = New Vector3(intX * mUnitSize, intY, intZ * mUnitSize)
                mVertex(intStart + intCounter + 2).Color = colColour2 : mVertex(intStart + intCounter + 2).Position = New Vector3(intX * mUnitSize, sngYLower, intZ * mUnitSize)
                mVertex(intStart + intCounter + 3).Color = colColour2 : mVertex(intStart + intCounter + 3).Position = New Vector3(intX * mUnitSize + mUnitSize, intY, intZ * mUnitSize)
                mVertex(intStart + intCounter + 4).Color = colColour2 : mVertex(intStart + intCounter + 4).Position = New Vector3(intX * mUnitSize, intY, intZ * mUnitSize)
                mVertex(intStart + intCounter + 5).Color = colColour2 : mVertex(intStart + intCounter + 5).Position = New Vector3(intX * mUnitSize + mUnitSize, sngYLower, intZ * mUnitSize)
                intCounter += 6
            End If
            ' Right Side
            If (blnRight) Then
                mVertex(intStart + intCounter).Color = colColour3 : mVertex(intStart + intCounter).Position = New Vector3(intX * mUnitSize + mUnitSize, sngYLower, intZ * mUnitSize)
                mVertex(intStart + intCounter + 1).Color = colColour3 : mVertex(intStart + intCounter + 1).Position = New Vector3(intX * mUnitSize + mUnitSize, sngYLower, intZ * mUnitSize + mUnitSize)
                mVertex(intStart + intCounter + 2).Color = colColour3 : mVertex(intStart + intCounter + 2).Position = New Vector3(intX * mUnitSize + mUnitSize, intY, intZ * mUnitSize + mUnitSize)
                mVertex(intStart + intCounter + 3).Color = colColour3 : mVertex(intStart + intCounter + 3).Position = New Vector3(intX * mUnitSize + mUnitSize, intY, intZ * mUnitSize)
                mVertex(intStart + intCounter + 4).Color = colColour3 : mVertex(intStart + intCounter + 4).Position = New Vector3(intX * mUnitSize + mUnitSize, sngYLower, intZ * mUnitSize)
                mVertex(intStart + intCounter + 5).Color = colColour3 : mVertex(intStart + intCounter + 5).Position = New Vector3(intX * mUnitSize + mUnitSize, intY, intZ * mUnitSize + mUnitSize)
                intCounter += 6
            End If
            ' Left Side
            If (blnLeft) Then
                mVertex(intStart + intCounter).Color = colColour4 : mVertex(intStart + intCounter).Position = New Vector3(intX * mUnitSize, sngYLower, intZ * mUnitSize + mUnitSize)
                mVertex(intStart + intCounter + 1).Color = colColour4 : mVertex(intStart + intCounter + 1).Position = New Vector3(intX * mUnitSize, sngYLower, intZ * mUnitSize)
                mVertex(intStart + intCounter + 2).Color = colColour4 : mVertex(intStart + intCounter + 2).Position = New Vector3(intX * mUnitSize, intY, intZ * mUnitSize)
                mVertex(intStart + intCounter + 3).Color = colColour4 : mVertex(intStart + intCounter + 3).Position = New Vector3(intX * mUnitSize, intY, intZ * mUnitSize + mUnitSize)                
                mVertex(intStart + intCounter + 4).Color = colColour4 : mVertex(intStart + intCounter + 4).Position = New Vector3(intX * mUnitSize, sngYLower, intZ * mUnitSize + mUnitSize)
                mVertex(intStart + intCounter + 5).Color = colColour4 : mVertex(intStart + intCounter + 5).Position = New Vector3(intX * mUnitSize, intY, intZ * mUnitSize)
            End If
        End If
    End Sub
    ''' <summary>
    ''' Allows the game component to perform any initialization it needs to before starting
    ''' to run.  This is where it can query for any required services and load content.
    ''' </summary>
    Public Overrides Sub Initialize()
        ' TODO: Add your initialization code here
        MyBase.Initialize()
    End Sub

    ''' <summary>
    ''' Allows the game component to update itself.
    ''' </summary>
    ''' <param name="gameTime">Provides a snapshot of timing values.</param>
    Public Overrides Sub Update(ByVal gameTime As GameTime)
        If (Not mdatLevel Is Nothing And Not mblnLevelNotified) Then
            If (mGameRun.CameraPosition.Z / mUnitSize > mdatLevel.Length / mWidth + Me.RowCount - 1) Then
                mblnLevelNotified = True
                RaiseEvent EndOfLevel()
            End If
        End If
        MyBase.Update(gameTime)
    End Sub
    ' //////////////////////////////////////////////////////////////////////////
    ' Finalise and clean up
    Protected Overrides Sub Finalize()
        mdatLevel = Nothing
        mVertex = Nothing
        mVBuffer = Nothing
        ' 
        MyBase.Finalize()
    End Sub
End Class
